package nc.bs.plugin;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.yonyou.ucf.mdf.util.BIPUtil;
import com.yonyou.ucf.mdf.util.HttpClientUtil;
import nc.bs.dao.BaseDAO;
import nc.bs.dao.DAOException;
import nc.bs.pub.pa.PreAlertObject;
import nc.bs.pub.taskcenter.BgWorkingContext;
import nc.bs.pub.taskcenter.IBackgroundWorkPlugin;
import nc.jdbc.framework.SQLParameter;
import nc.jdbc.framework.processor.MapListProcessor;
import nc.vo.pub.BusinessException;
import nc.vo.pub.lang.UFDateTime;
import ncc.bs.utils.GetParamConfigUtil;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 拉取【友费控】的【单据信息关键字】保存到中间表【budget_keyword_xmheart】
 * 单据范围保存在本系统的XMHeart_keyword自定义档案里面
 *
 * @author ouyanggx
 * @date 2025/9/8
 * */
public class GetBudgetKeywordPlugin implements IBackgroundWorkPlugin {

    // 中间表
    private final String TABLE_NAME = "budget_keyword_xmheart";

    private final Integer DEFAULT_PAGE_SIZE = 100;

    private DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

    private Logger logger = LoggerFactory.getLogger(GetBudgetKeywordPlugin.class);

    private String yfkIP;
    public String getYfkIP() {
        if (yfkIP == null) {
            yfkIP = GetParamConfigUtil.queryGroupSysParam("YFKIP");
        }
        return yfkIP;
    }

    private BaseDAO dao;
    private BaseDAO getDAO() {
        if (dao == null) {
            dao = new BaseDAO();
        }
        return dao;
    }

    @Override
    public PreAlertObject executeTask(BgWorkingContext bgWorkingContext) throws BusinessException {
        try {
            // 后台任务参数
            Map<String, Object> params = bgWorkingContext.getKeyMap();
            String action = params.get("action") == null ? "NORMOAL" : params.get("action").toString();
            String beginDate = (String) params.get("beginDate");// 单据日期开始时间
            String endDate = (String) params.get("endDate");// 单据日期结束时间
            if (StringUtils.isEmpty((String) params.get("appkey"))
                    || StringUtils.isEmpty((String) params.get("appsecret"))) {
                throw new BusinessException("友费控信息必填appkey,appsecret");
            }
            if (StringUtils.isEmpty((String) params.get("bills"))) {
                throw new BusinessException("单据信息必须勾选");
            }

            switch (action) {
                case "GETALL":// 获取全部数据
                    // 先清表
                    truncateTable();

                    doAction(null, null, params);
                    break;
                case "NORMOAL":// 日常操作，默认拉取昨天的单据
                    // 获取今天日期
                    LocalDate today = LocalDate.now();
                    // 获取昨天日期
                    LocalDate yesterday = today.minusDays(1);
                    // 格式化输出
                    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
                    String formattedYesterday = yesterday.format(formatter);

                    doAction(formattedYesterday + " 00:00:00", formattedYesterday + " 23:59:59", params);
                    break;
                case "APPOINTED":// 指定日期
                    if (beginDate == null && endDate == null) {
                        throw new BusinessException("[APPOINTED]动作必须填写开始日期或者结束日期");
                    }

                    validateDateFormat(beginDate, endDate);// 检查输入日期格式

                    if (beginDate != null && endDate != null) {
                        LocalDateTime begin = LocalDateTime.parse(beginDate, dateTimeFormatter);
                        LocalDateTime end = LocalDateTime.parse(endDate, dateTimeFormatter);
                        int result = begin.compareTo(end);
                        if (result > 0) {
                            throw new BusinessException("检查日期参数先后顺序");
                        }
                    } else if (beginDate != null && endDate == null) {
                        endDate = beginDate;
                    } else if (beginDate == null && endDate != null) {
                        beginDate = endDate;
                    }

                    doAction(beginDate, endDate, params);

                    break;
                case "TRUNCATE":// 清表
                    truncateTable();
                    break;
                case "CREATETABLE":// 建表
                    createTable();
                    break;
                default:
                    throw new BusinessException("错误的动作请输入正确的动作值[GETALL, NORMOAL, APPOINTED, TRUNCATE, CREATETABLE]");
            }
        } catch (Exception e) {
            logger.error("拉取友费控关键字报错", e);
            throw new BusinessException(e.getMessage());
        }
        return null;
    }

    /**
     * 获取单据信息，code用于拼接API地址，mnecode为关键词字段
     * */
    private List<Map<String, String>> getBillInfo(String[] bills) throws DAOException {
        String sql = "select code,memo from bd_defdoc where pk_defdoc in ('" + String.join("','", bills) + "')";
        return (List<Map<String, String>>) getDAO().executeQuery(sql, new MapListProcessor());
    }

    /**
     * 拉取通用报销单关键字
     * */
    private void doAction(String beginDate, String endDate, Map<String, Object> params) throws BusinessException {

        JSONObject reqBody =  new JSONObject();

        if (beginDate != null && endDate != null) {
            reqBody.put("pubts", beginDate + "|" + endDate);
        }

        if (StringUtils.isNotEmpty((String) params.get("code"))) {
            reqBody.put("code", (String) params.get("code"));
        }

        // 获取同步的单据信息
        String[] bills = params.get("bills").toString().split(",");
        List<Map<String, String>> billList = getBillInfo(bills);
        for (Map<String, String> billInfo : billList) {
            int pageIndex = 0;
            int pageCount = 1;
            do {
                pageIndex++;
                JSONObject  resp = reqExpensebillList(reqBody, DEFAULT_PAGE_SIZE, pageIndex, params, billInfo.get("code"));
                pageCount = resp.getInteger("pageCount");// 总页数
                processInsert(resp, billInfo.get("memo"));// 执行插入
            } while (pageCount > pageIndex);
        }
    }

    /**
     * 执行插入操作
     * */
    private void processInsert(JSONObject data, String gjcKey) throws BusinessException {
        StringBuilder builder = new StringBuilder(" MERGE INTO ");
        builder.append(TABLE_NAME).append(" target USING ( ");

        JSONArray jsonArray = data.getJSONArray("recordList");
        if  (jsonArray == null || jsonArray.size() < 1) {
            return;
        }

        List<String> billCodeList = new ArrayList();
        SQLParameter sqlParameter = new SQLParameter();
        String billcode;
        for (int i = 0; i < jsonArray.size(); i++) {
            JSONObject item = jsonArray.getJSONObject(i);

            billcode = item.getString("code");

            if (!billCodeList.contains(billcode)) {
                if (i==0) {
                    builder.append(" SELECT ? AS billcode, ? AS keyword, ? AS ts FROM DUAL ");
                } else {
                    builder.append(" UNION ALL ");
                    builder.append(" SELECT ?,?,? FROM DUAL ");
                }

                sqlParameter.addParam(billcode);
                sqlParameter.addParam(item.getString(gjcKey));
                sqlParameter.addParam(new UFDateTime().toLocalString());
            }

            billCodeList.add(billcode);
        }

        builder.append(" ) source ON (target.billcode=source.billcode) ");
        builder.append(" WHEN MATCHED THEN ");
        builder.append(" UPDATE SET target.keyword=source.keyword, target.ts=source.ts ");
        builder.append(" WHEN NOT MATCHED THEN ");
        builder.append(" INSERT (billcode,keyword,ts) VALUES (source.billcode, source.keyword, source.ts) ");

        try {
            getDAO().executeUpdate(builder.toString(), sqlParameter);
        } catch (DAOException e) {
            throw new BusinessException(e.getMessage());
        }
    }

    /**
     * 用中转机发送请求（内网环境）
     * */
    private String zzjRequest(String appkey, String appsecret, String zzjIP, String yfkURI,
                              JSONObject data) throws BusinessException {
        // 中转机
        JSONObject reqBody =  new JSONObject();
        reqBody.put("appKey", appkey);
        reqBody.put("appSecret", appsecret);
        reqBody.put("ywURL", yfkURI);
        reqBody.put("data", data);
        return HttpClientUtil.doPost(zzjIP+ "/yfkService/tbYFK",null, null, reqBody);
    }

    /**
     * 直接请求友费控（外网环境)
     * */
    private String yfkRequest(String appkey, String appsecret, String yfkURI, JSONObject reqBody) throws BusinessException {
        Map<String, Object> reqParams = new HashMap<String, Object>();
        reqParams.put("access_token", getToken(appkey, appsecret));
        return HttpClientUtil.doPost(yfkURI,null, reqParams, reqBody);
    }

    private String getToken(String appkey, String appsecret) throws BusinessException {
        // 获取token
        String accessToken = BIPUtil.getAccessToken(getYfkIP() + "/iuap-api-auth/open-auth/selfAppAuth/getAccessToken",
                appkey, appsecret);
        if (accessToken == null || "".equals(accessToken)) {
            throw new BusinessException("获取accessToken出错");
        }
        return accessToken;
    }

    /**
     * 查询友费控通用报销单信息
     * */
    private JSONObject reqExpensebillList(JSONObject reqBody, Integer pageSize,
                                         Integer pageIndex, Map<String, Object> params, String bill) throws BusinessException {

        reqBody.put("pageSize", pageSize);
        reqBody.put("pageIndex", pageIndex);

        String yfkURI = getYfkIP() + "/iuap-api-gateway/yonbip/znbz/rbsm/api/bill/" + bill + "/list";
        String appkey = (String) params.get("appkey");
        String appsecret = (String) params.get("appsecret");

        String zzjIP = (String) params.get("reqIp");
        String response = null;
        if (StringUtils.isNotEmpty(zzjIP)) {
            // 中转机
            response = zzjRequest(appkey, appsecret,  (String) params.get("reqIp"), yfkURI, reqBody);
        } else {
            // 外网
            response = yfkRequest(appkey, appsecret, yfkURI, reqBody);
        }

        JSONObject jsonObject = JSONObject.parseObject(response);
        if ("200".equals(jsonObject.getString("code"))) {
            return jsonObject.getJSONObject("data");
        } else {
            throw new BusinessException(jsonObject.getString("message"));
        }
    }

    private void validateDateFormat(String... input) throws BusinessException {
        if (Arrays.stream(input).filter(item -> item!=null)
                .allMatch(item -> {
                    try {
                        LocalDate.parse(item, dateTimeFormatter);
                        return false;
                    } catch (DateTimeParseException e) {
                        return true;
                    }
                })) {
            throw new BusinessException("日期格式需为yyyy-MM-dd HH:mm:ss");
        }
    }

    private void truncateTable() throws BusinessException {
        getDAO().executeUpdate(" truncate table " + TABLE_NAME);
    }

    private void createTable() throws BusinessException {
        String sql = "CREATE TABLE " + TABLE_NAME +
                "( billcode varchar(50) primary key not null, " +
                "keyword varchar(2000), ts varchar(19) not null) ";
        getDAO().executeUpdate(sql);
    }
}
